package com.jry.job.util;

import com.jry.job.domain.SysJob;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import com.jry.common.core.constant.Constants;
import com.jry.common.core.constant.ScheduleConstants;
import com.jry.common.core.exception.job.TaskException;
import com.jry.common.core.exception.job.TaskException.Code;
import com.jry.common.core.utils.StringUtils;

/**
 * 定时任务工具类
 *
 * @author zhangsuhang
 */
public class ScheduleUtils {

  /**
   * 得到quartz任务类
   *
   * @param sysJob 执行计划
   * @return 具体执行任务类
   */
  private static Class<? extends Job> getQuartzJobClass(SysJob sysJob) {
    boolean isConcurrent = "0".equals(sysJob.getConcurrent());
    return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
  }

  /**
   * 构建任务触发对象
   */
  public static TriggerKey getTriggerKey(Long jobId, String jobGroup) {
    return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
  }

  /**
   * 构建任务键对象
   */
  public static JobKey getJobKey(Long jobId, String jobGroup) {
    return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
  }

  /**
   * 创建定时任务
   */
  public static void createScheduleJob(Scheduler scheduler, SysJob job)
      throws SchedulerException, TaskException {
    Class<? extends Job> jobClass = getQuartzJobClass(job);
    // 构建job信息
    Long jobId = job.getJobId();
    String jobGroup = job.getJobGroup();
    JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup))
        .build();

    // 表达式调度构建器
    CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
        .cronSchedule(job.getCronExpression());
    cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);

    // 按新的cronExpression表达式构建一个新的trigger
    CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup))
        .withSchedule(cronScheduleBuilder).build();

    // 放入参数，运行时的方法可以获取
    jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);

    // 判断是否存在
    if (scheduler.checkExists(getJobKey(jobId, jobGroup))) {
      // 防止创建时存在数据问题 先移除，然后在执行创建操作
      scheduler.deleteJob(getJobKey(jobId, jobGroup));
    }

    scheduler.scheduleJob(jobDetail, trigger);

    // 暂停任务
    if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) {
      scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
    }
  }

  /**
   * 设置定时任务策略
   */
  public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job,
      CronScheduleBuilder cb)
      throws TaskException {
    switch (job.getMisfirePolicy()) {
      case ScheduleConstants.MISFIRE_DEFAULT:
        return cb;
      case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
        return cb.withMisfireHandlingInstructionIgnoreMisfires();
      case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
        return cb.withMisfireHandlingInstructionFireAndProceed();
      case ScheduleConstants.MISFIRE_DO_NOTHING:
        return cb.withMisfireHandlingInstructionDoNothing();
      default:
        throw new TaskException("The task misfire policy '" + job.getMisfirePolicy()
            + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR);
    }
  }

  /**
   * 检查包名是否为白名单配置
   *
   * @param invokeTarget 目标字符串
   * @return 结果
   */
  public static boolean whiteList(String invokeTarget) {
    String packageName = StringUtils.substringBefore(invokeTarget, "(");
    int count = StringUtils.countMatches(packageName, ".");
    if (count > 1) {
      if (!StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR)) {
        return false;
      }
    }
    return true;
  }
}
